package com.wangxiaonan.coupon.service.impl;

import com.wangxiaonan.coupon.common.Constant;
import com.wangxiaonan.coupon.common.exception.ServiceException;
import com.wangxiaonan.coupon.config.RedisManeger;
import com.wangxiaonan.coupon.domain.CouponInfo;
import com.wangxiaonan.coupon.repository.CouponInfoDao;
import com.wangxiaonan.coupon.service.CouponInfoService;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Resource;
import javax.transaction.Transactional;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

@Service
@Transactional
public class CouponInfoServiceImpl implements CouponInfoService {

    @Resource
    private CouponInfoDao couponInfoDao;

    /**
     * 时间之间相差的秒数
     * <p>
     * end - start
     * </p>
     */
    public static int getSecond(Date start, Date end) {
        if (start == null || end == null) {
            throw new NullPointerException("date is null");
        }
        return (int) ((end.getTime() - start.getTime()) / 1000);
    }

    @Cacheable(value = "coupon_infos", key = "'coupon.info.'+#id")
    @Override
    public CouponInfo findById(Integer id) {
        Optional<CouponInfo> optional = couponInfoDao.findById(id);
        return optional.orElse(null);
    }

    @Override
    public CouponInfo save(CouponInfo entity) {
        Assert.notNull(entity, "entity 不能为空");
        if (entity.getStatus() == null) {
            entity.setStatus(0);
        }
        return couponInfoDao.save(entity);
    }

    @CacheEvict(value = "coupon_infos", key = "'coupon.info.'+#id")
    @Override
    public void deleteById(Integer id) {
        couponInfoDao.deleteById(id);
    }

    @CacheEvict(value = "coupon_infos", key = "'coupon.info.'+#entity.id")
    @Override
    public CouponInfo update(CouponInfo entity) {
        Assert.notNull(entity, "entity 不能为空");
        Assert.notNull(entity.getId(), "entity.id 不能为空");
        return couponInfoDao.save(entity);
    }

    @Override
    public boolean publish(CouponInfo info) {
        Assert.notNull(info, "info 不能为空");
        Assert.notNull(info.getId(), "info.id 不能为空");
        AtomicBoolean flag = new AtomicBoolean(false);
        Optional<CouponInfo> option = couponInfoDao.findById(info.getId());
        option.ifPresent(couponInfo -> {
            if (couponInfo.getStatus() == 1) {
                throw new ServiceException("coupon is already published");
            }
            couponInfo.setStatus(1);// 1:发布
            // create info queue
            RedisManeger.pipelineOperate(pipeline -> {
                // TODO 可以加上管道事务，性能介于管道和事务处理之间
                String queueKey = Constant.COUPON_INFO_QUEUE_PREFIX + couponInfo.getId();
                pipeline.lpush(queueKey, couponNumGenerator(info).toArray(new String[]{}));
                int second = getSecond(new Date(), info.getExpireDate());
                pipeline.expire(queueKey, second);
                String circulationKey = Constant.COUPON_CIRCULATION_PREFIX + info.getId();
                pipeline.set(circulationKey, String.valueOf(info.getCirculation()));
                pipeline.expire(circulationKey, second);
            });

            flag.set(true);
        });
        return flag.get();
    }

    /**
     * 优惠券唯一编码生成器
     */
    private List<String> couponNumGenerator(CouponInfo info) {
        // 发行量
        int circulation = info.getCirculation();
        List<String> couponNums = new ArrayList<>();
        for (int i = 0; i < circulation; i++) {
            // 生成优惠券唯一编码
            couponNums.add(UUID.randomUUID().toString());
        }
        return couponNums;
    }
}
